<?php

class Apiorder extends ApiBase {
	private $user_id;
	private $configs;
	public function __construct(){
		parent::__construct();
		
		$method=$this->uri->segment(2);
		if($method!=='notify'){
		$this->user_id=$this->GetUser()['user_id'];
		}
		$wxapp=$this->db->get('wxapp')->row_array();
		$this->configs=$wxapp;
	}
     
    public function invoice(){
    	$post=$this->input->post();
    	$post['user_id']=$this->user_id;
    	unset($post['token']);
        $res=$this->db->insert('invoice',$post);
        $invoice=$this->db->insert_id();
        if($res){
       	$this->show(array('code'=>1,'msg'=>'添加成功','invoice'=>$invoice));	
        }else{
        $this->show(array('code'=>0,'msg'=>'添加失败'));	
        }
    	
    }
    
    
       //查快递
      public function express($express_code,$express_no){
          //参数设置
          $key = 'RQBSzsuB4408';						//客户授权key
          $customer = '6B77D43C6B6CD8663296E79C515B8730';					//查询公司编号
          $param = array (
              'com' =>$express_code,			//快递公司编码
              'num' =>$express_no,	//快递单号
              'phone' => '',				//手机号
              'from' => '',				//出发地城市
              'to' => '',					//目的地城市
              'resultv2' => '1'			//开启行政区域解析
          );

          //请求参数
          $post_data = array();
          $post_data["customer"] = $customer;
          $post_data["param"] = json_encode($param);
          $sign = md5($post_data["param"].$key.$post_data["customer"]);
          $post_data["sign"] = strtoupper($sign);

          $url = 'http://poll.kuaidi100.com/poll/query.do';	//实时查询请求地址

          $params = "";
          foreach ($post_data as $k=>$v) {
              $params .= "$k=".urlencode($v)."&";		//默认UTF-8编码格式
          }
          $post_data = substr($params, 0, -1);
          //发送post请求
          $ch = curl_init();
          curl_setopt($ch, CURLOPT_POST, 1);
          curl_setopt($ch, CURLOPT_HEADER, 0);
          curl_setopt($ch, CURLOPT_URL, $url);
          curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
          $result = curl_exec($ch);
          $data = str_replace("\"", '"', $result );
          $data = json_decode($data,true);
          return $data;
      }
      
	public function index(){
        $where['user_id']=$this->user_id;
        $status=$this->uri->segment(4);
        switch ($status){
			case 10:
				$where['order_status']=10;
				break;
			case 20:
				$where['order_status']=20;
				break;
			case 30:
				$where['order_status']=30;
				break;
			case 40:
				$where['order_status']=40;
				break;
		}
		$list=$this->db->select('order_id,order_no,order_status,expenses,pay_price,create_time')->where($where)->order_by('create_time desc')->get('order')->result_array();
        foreach ($list as $k=>$v){
		$list[$k]['goods']=$this->db->where('order_id',$v['order_id'])->get('order_goods')->result_array();
		$list[$k]['create_time']=date('Y-m-d H:i:s',$v['create_time']);
		}

        if(empty($list)){
			$this->show(array('code'=>0,'msg'=>'暂无订单数据'));
		}

        $this->show($list);
	}
     
     
    public function del(){
	$where['order_id']=(int)$this->input->post()['order_id'];
	$this->db->trans_begin();
    $this->db->where($where)->delete('order');
    $this->db->where($where)->delete('order_address');
    $this->db->where($where)->delete('order_goods');
if ($this->db->trans_status() === FALSE){
    $this->db->trans_rollback();
      $this->show(array('code'=>0,'msg'=>'删除失败'));
}else{
    $this->db->trans_commit();
      $this->show(array('code'=>1,'msg'=>'删除成功'));
}
	}
	

     public function comfirm(){
     $post=$this->input->post();
     $where['order_id']=$post['order_id'];
     $data['order_status']=40;
     $res=$this->db->where($where)->update('order',$data);
     if($res){
     $this->show(array('code'=>1,'msg'=>'确认成功'));	
     }else{
     $this->show(array('code'=>0,'msg'=>'确认失败'));		
       }
     }
     
     
      public function cancel(){
     $post=$this->input->post();
     $where['order_id']=$post['order_id'];
     $data['order_status']=50;
     $res=$this->db->where($where)->update('order',$data);
     if($res){
     $this->show(array('code'=>1,'msg'=>'取消成功'));	
     }else{
     $this->show(array('code'=>0,'msg'=>'取消失败'));		
       }
     }
   
   
   
         public function back(){
     $post=$this->input->post();
     $where['order_id']=$post['order_id'];
     $data['order_status']=60;
     $res=$this->db->where($where)->update('order',$data);
     if($res){
     $this->show(array('code'=>1,'msg'=>'取消成功'));	
     }else{
     $this->show(array('code'=>0,'msg'=>'取消失败'));		
       }
     }
   
   
	public function detail(){
	    $where['order_id']=(int)$this->uri->segment(4);
	    $where['user_id']=$this->user_id;

		$list=$this->db->select('order_id,order_no,order_status,expenses,pay_price,create_time,express_code,number,invoice,express')->where($where)->get('order')->row_array();
		$list['create_time']=date('Y-m-d H:i:s',$list['create_time']);
		$list['goods']=$this->db->where('order_id',$list['order_id'])->get('order_goods')->result_array();

		$address=$this->db->select('name,phone,province,city,region,detail')->where($where)->get('order_address')->row_array();
		$express=$this->express($list['express_code'],$list['number']);
		
		
		$invoice=$this->db->where('id',$list['invoice'])->get('invoice')->row_array();;
		$this->show(array('order'=>$list,'address'=>$address,'express'=>$express,'invoice'=>$invoice));
	}

    
     public function pay(){
     	$post=$this->input->post();
     	$where['order_id']=$post['order_id'];
     	$order=$this->db->where($where)->get('order')->row_array();
     	if($order){
     		$res=$this->unifiedorder($order['order_no'],$this->GetUser()['openid'],$order['pay_price']);
     		$this->show(array('code'=>1,'msg'=>$res));
     	}else{
     		$this->show(array('code'=>0,'msg'=>'订单不存在'));
     	}
     	
     	
     }

  
	public function buynow(){
        if ($this->post()){
         $post=$this->input->post();
         if (is_null($post['address_id'])) {
        	$this->show(array('code'=>0,'msg'=>'收货地址不能为空'));
         }
         
         $post['user_id']=$this->user_id;
		 $goods=$this->GetGoods($post['goods_id'],$post['sku']);
		 $address=$this->db->where('address_id',$post['address_id'])->get('address')->row_array();

		 $this->db->trans_begin();
		 $order['order_no']=$this->orderNo();
		 $order['pay_price']=$post['goods_num']*$goods['goods_price'];
		 $order['user_id']=$this->user_id;
		 $order['create_time']=time();
		 $order['invoice']=$post['invoice'];
		 $this->db->insert('order',$order);
		 $order_id=$this->db->insert_id();

		 $address['order_id']=$order_id;
		 unset($address['default']);
		 unset($address['address_id']);
		 $this->db->insert('order_address',$address);

		$goods['order_id']=$order_id;
		$goods['goods_num']=$post['goods_num'];
		$this->db->insert('order_goods',$goods);

		$res=$this->unifiedorder($order['order_no'],$this->GetUser()['openid'],$order['pay_price']);

		if ($this->db->trans_status() === FALSE) {
			$this->db->trans_rollback();
			$this->show(array('code'=>0,'msg'=>'提交失败'));
			}else {
			$this->db->trans_commit();
			$this->show(array('code'=>1,'msg'=>$res));
			}
		}else{
        $post['user_id']=$this->user_id;
		$post['goods_id']=$this->uri->segment(4);
		$post['goods_num']=$this->uri->segment(5);
		$post['sku']=$this->uri->segment(6);
		 //地址
		$map['user_id']=$this->user_id;
		$map['default']=10;
		$address=$this->db->where($map)->get('address')->row_array();
        $goods=$this->GetGoods($post['goods_id'],$post['sku']);
		$goods['goods_num']=$post['goods_num'];
	 	$this->show(array('address'=>$address,'goods'=>$goods));
		}
	}


	public function buycart(){
		if ($this->post()){
          $post=$this->input->post();
          
            if (is_null($post['address_id'])) {
        	$this->show(array('code'=>0,'msg'=>'收货地址不能为空'));
         }
          
		  $cart=explode('_',$post['cart_id']);
			$cartdata=array();
			foreach ($cart as $k=>$v){
				$carts=$this->db->where('id',$v)->get('cart')->row_array();
				if (!empty($carts)){
					array_push($cartdata,$carts);
				}
			}

			$goods=array();
			foreach ($cartdata as $k=>$v){
				$data=$this->GetGoods($v['goods_id'],$v['sku']);
				$data['goods_num']=$v['goods_num'];
				$data['sku']=$v['sku'];
				$data['pay_price']=$v['goods_num']*$data['goods_price'];
				array_push($goods,$data);
			}

			$address=$this->db->where('address_id',$post['address_id'])->get('address')->row_array();

			$this->db->trans_begin();
	/*--------------------------------------------*/
			$order['order_no']=$this->orderNo();
			$order['pay_price']=array_sum(array_column($goods, 'pay_price'));
			$order['user_id']=$this->user_id;
			$order['create_time']=time();
			 $order['invoice']=$post['invoice'];
			$this->db->insert('order',$order);
			$order_id=$this->db->insert_id();

			$address['order_id']=$order_id;
			unset($address['default']);
			unset($address['address_id']);
			$this->db->insert('order_address',$address);

			foreach ($goods as $k=>$v){
				$goodsdata['order_id']=$order_id;
				$goodsdata['goods_id']=$v['goods_id'];
				$goodsdata['goods_name']=$v['goods_name'];
				$goodsdata['goods_num']=$v['goods_num'];
				$goodsdata['image']=$v['image'];
				$goodsdata['goods_price']=$v['goods_price'];
				$goodsdata['sku']=$v['sku'];
				$this->db->insert('order_goods',$goodsdata);
			}

			foreach ($cart as $v){
				$this->db->delete('cart',array('id'=>$v));
			}
			
			$res=$this->unifiedorder($order['order_no'],$this->GetUser()['openid'],$order['pay_price']);
	/*--------------------------------------------------------*/

			if ($this->db->trans_status() === FALSE) {
				$this->db->trans_rollback();
				$this->show(array('code'=>0,'msg'=>'提交失败'));
			}else {
				$this->db->trans_commit();
				$this->show(array('code'=>1,'msg'=>$res));
			}



		}else{
		$cart=$this->uri->segment(4);
		$cart=explode('_',$cart);
		$cartdata=array();
		foreach ($cart as $k=>$v){
			$carts=$this->db->where('id',$v)->get('cart')->row_array();
			if (!empty($carts)){
				array_push($cartdata,$carts);
			}
		}
		$goods=array();
		foreach ($cartdata as $k=>$v){
			$data=$this->GetGoods($v['goods_id'],$v['sku']);
			$data['goods_num']=$v['goods_num'];
			array_push($goods,$data);
		}

			//地址
			$map['user_id']=$this->user_id;
			$map['default']=10;
			$address=$this->db->where($map)->get('address')->row_array();
			$this->show(array('address'=>$address,'goods'=>$goods));
		}

	}



   public function GetGoods($goods_id,$sku){
	   $goods=$this->db->select('goods_id,goods_name')->where('goods_id',$goods_id)->get('goods')->row_array();
	   $img=$this->GetGoodsImage($goods_id);
	   if (!empty($img)){
		   $goods['image']=$this->GetImg($img[0]['image_id']);
	   }else{
		   $goods['image']='';
	   }
	   $goods['goods_price']=$this->getSkuPrice($sku);
	   return $goods;
   }

    


	protected function orderNo(){
		return date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
	}
      
      
       
	/**
	 * 统一下单API
	 * @param $order_no
	 * @param $openid
	 * @param $total_fee
	 * @return array
	 * @throws BaseException
	 */
	public function unifiedorder($order_no, $openid, $total_fee){
		// 当前时间
		$time = time();
		// 生成随机字符串
		$nonceStr = md5($time . $openid);
		// API参数
		$params = array(
			'appid' => $this->configs['AppID'],
			'attach' => 'test',
			'body' => $order_no,
			'mch_id' => $this->configs['mchid'],
			'nonce_str' => $nonceStr,
			'notify_url' =>'https://'.$_SERVER['HTTP_HOST'].'/Apiorder/notify',  // 异步通知地址
			'openid' => $openid,
			'out_trade_no' => $order_no,
			'spbill_create_ip' => $_SERVER["REMOTE_ADDR"],
			'total_fee' => $total_fee * 100, // 价格:单位分
			'trade_type' => 'JSAPI',
		);
		// 生成签名
		$params['sign'] = $this->makeSign($params);
		// 请求API
		$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
		$result = $this->posts($url, $this->toXml($params));

		$prepay = $this->fromXml($result);

		// 请求失败
		if ($prepay['return_code'] === 'FAIL') {
			$this->show(array('msg' => $prepay['return_msg'], 'code' => -10));
		}
		if ($prepay['result_code'] === 'FAIL') {
			$this->show(array('msg' => $prepay['err_code_des'], 'code' => -10));
		}
		// 生成 nonce_str 供前端使用
		$paySign = $this->makePaySign($params['nonce_str'], $prepay['prepay_id'], $time);
		return array(
			'prepay_id' => $prepay['prepay_id'],
			'nonceStr' => $nonceStr,
			'timeStamp' => (string)$time,
			'paySign' => $paySign
		);
	}


	/**
	 * 支付成功异步通知
	 * @param \app\task\model\Order $OrderModel
	 * @throws BaseException
	 * @throws \Exception
	 * @throws \think\exception\DbException
	 */
	public function notify(){
//        $xml = <<<EOF
//<xml><appid><![CDATA[wxe1997e687ecca54e]]></appid>
//<attach><![CDATA[test]]></attach>
//<bank_type><![CDATA[CFT]]></bank_type>
//<cash_fee><![CDATA[100]]></cash_fee>
//<fee_type><![CDATA[CNY]]></fee_type>
//<is_subscribe><![CDATA[N]]></is_subscribe>
//<mch_id><![CDATA[1509822581]]></mch_id>
//<nonce_str><![CDATA[c1e4cca2a8a9f18f4b45ee2ada267bf5]]></nonce_str>
//<openid><![CDATA[o0-ZJ5DHAEkK-yKcsz80lZnzq0xY]]></openid>
//<out_trade_no><![CDATA[2018091498495110]]></out_trade_no>
//<result_code><![CDATA[SUCCESS]]></result_code>
//<return_code><![CDATA[SUCCESS]]></return_code>
//<sign><![CDATA[8A8403FAF9E3732BB09BED12C4AE0ABC]]></sign>
//<time_end><![CDATA[20180914134610]]></time_end>
//<total_fee>100</total_fee>
//<trade_type><![CDATA[JSAPI]]></trade_type>
//<transaction_id><![CDATA[4200000182201809147560430045]]></transaction_id>
//</xml>
//EOF;
		if (!$xml = file_get_contents('php://input')) {
			$this->returnCode(false, 'Not found DATA');
			
		}
		// 将服务器返回的XML数据转化为数组
		$data = $this->fromXml($xml);
	

		// 记录日志
//		$this->doLogs($xml);
//		$this->doLogs($data);

		// 保存微信服务器返回的签名sign
		$dataSign = $data['sign'];
		// sign不参与签名算法
		unset($data['sign']);
		// 生成签名
		$sign = $this->makeSign($data);
		// 判断签名是否正确  判断支付状态
		if (($sign === $dataSign)
			&& ($data['return_code'] == 'SUCCESS')
			&& ($data['result_code'] == 'SUCCESS')) {
			// 订单支付成功业务处理
            $Where['order_no']=$data['out_trade_no'];
            $update['order_status']=20;
            $update['pay_time']=time();
            $update['transaction_id']=$data['transaction_id'];
            
            $this->db->where($Where)->update('order', $update);
			// 返回状态
			$this->returnCode(true, 'OK');
		}
		// 返回状态
		$this->returnCode(false, '签名失败');
	}

	/**
	 * 申请退款API
	 * @param $transaction_id
	 * @param  double $total_fee 订单总金额
	 * @param  double $refund_fee 退款金额
	 * @return bool
	 * @throws BaseException
	 */
	public function refund($transaction_id, $total_fee, $refund_fee){
		// 当前时间
		$time = time();
		// 生成随机字符串
		$nonceStr = md5($time . $transaction_id . $total_fee . $refund_fee);
		// API参数
		$params = array(
			'appid' => $this->appId,
			'mch_id' => $this->configs['mchid'],
			'nonce_str' => $nonceStr,
			'transaction_id' => $transaction_id,
			'out_refund_no' => $time,
			'total_fee' => $total_fee * 100,
			'refund_fee' => $refund_fee * 100,
		);
		// 生成签名
		$params['sign'] = $this->makeSign($params);
		// 请求API
		$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
		$result = $this->post($url, $this->toXml($params), true, $this->getCertPem());
		$prepay = $this->fromXml($result);
		// 请求失败
		if ($prepay['return_code'] === 'FAIL') {
			$this->show(array('msg' => 'return_msg: ' . $prepay['return_msg']));
		}
		if ($prepay['result_code'] === 'FAIL') {
			$this->show(array('msg' => 'err_code_des: ' . $prepay['err_code_des']));
		}
		return true;
	}

	/**
	 * 获取cert证书文件
	 * @return array
	 * @throws BaseException
	 */
	private function getCertPem(){
		if (empty($this->configs['cert_pem']) || empty($this->configs['key_pem'])) {
			$this->show(array('msg' => '请先到后台小程序设置填写微信支付证书文件'));
		}
		// cert目录
		$filePath = __DIR__ . '/cert/' . $this->configs['wxapp_id'] . '/';
		!is_dir($filePath) && mkdir($filePath, 0755, true);
		$certPem = $filePath . 'cert.pem';
		!file_exists($certPem) && file_put_contents($certPem, $this->configs['cert_pem']);
		$keyPem = $filePath . 'key.pem';
		!file_exists($keyPem) && file_put_contents($keyPem, $this->configs['key_pem']);
		return compact('certPem', 'keyPem');
	}



	/**
	 * 返回状态给微信服务器
	 * @param boolean $return_code
	 * @param string $msg
	 */
	private function returnCode($return_code = true, $msg = null){
		// 返回状态
		$return = array(
			'return_code' => $return_code ? 'SUCCESS' : 'FAIL',
			'return_msg' => $msg ?: 'OK',
		);
		// 记录日志
		// $this->log_write(array(
		// 	'describe' => '返回微信支付状态',
		// 	'data' => $return
		// ));
		die($this->toXml($return));
	}

	/**
	 * 生成paySign
	 * @param $nonceStr
	 * @param $prepay_id
	 * @param $timeStamp
	 * @return string
	 */
	private function makePaySign($nonceStr, $prepay_id, $timeStamp){
		$data = array(
			'appId' =>$this->configs['AppID'],
			'nonceStr' => $nonceStr,
			'package' => 'prepay_id=' . $prepay_id,
			'signType' => 'MD5',
			'timeStamp' => $timeStamp,
		);
		// 签名步骤一：按字典序排序参数
		ksort($data);
		$string = $this->toUrlParams($data);
		// 签名步骤二：在string后加入KEY
		$string = $string . '&key=' . $this->configs['apikey'];
		// 签名步骤三：MD5加密
		$string = md5($string);
		// 签名步骤四：所有字符转为大写
		$result = strtoupper($string);
		return $result;
	}

	/**
	 * 将xml转为array
	 * @param $xml
	 * @return mixed
	 */
	private function fromXml($xml){
		// 禁止引用外部xml实体
		libxml_disable_entity_loader(true);
		return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
	}

	/**
	 * 生成签名
	 * @param $values
	 * @return string 本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
	 */
	private function makeSign($values)
	{
		//签名步骤一：按字典序排序参数
		ksort($values);
		$string = $this->toUrlParams($values);
		//签名步骤二：在string后加入KEY
		$string = $string . '&key=' . $this->configs['apikey'];
		//签名步骤三：MD5加密
		$string = md5($string);
		//签名步骤四：所有字符转为大写
		$result = strtoupper($string);
		return $result;
	}

	/**
	 * 格式化参数格式化成url参数
	 * @param $values
	 * @return string
	 */
	private function toUrlParams($values){
		$buff = '';
		foreach ($values as $k => $v) {
			if ($k != 'sign' && $v != '' && !is_array($v)) {
				$buff .= $k . '=' . $v . '&';
			}
		}
		return trim($buff, '&');
	}

	/**
	 * 输出xml字符
	 * @param $values
	 * @return bool|string
	 */
	private function toXml($values){
		if (!is_array($values)
			|| count($values) <= 0
		) {
			return false;
		}

		$xml = "<xml>";
		foreach ($values as $key => $val) {
			if (is_numeric($val)) {
				$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
			} else {
				$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
			}
		}
		$xml .= "</xml>";
		return $xml;
	}

	/**
	 * 模拟POST请求
	 * @param $url
	 * @param array $data
	 * @param bool $useCert
	 * @param array $sslCert
	 * @return mixed
	 */
	public function posts($url, $data =array(), $useCert = false, $sslCert =array()){
		$header = array('Content-type: application/json;');
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
		curl_setopt($curl, CURLOPT_HEADER, false);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($curl, CURLOPT_POST, TRUE);
		curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
		if ($useCert == true) {
			// 设置证书：cert 与 key 分别属于两个.pem文件
			curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
			curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);
			curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
			curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);
		}
		$result = curl_exec($curl);
		curl_close($curl);
		return $result;
	}

	/**
	 * 写入日志记录
	 * @param $values
	 * @return bool|int
	 */
	protected function doLogs($values)
	{
		return write_log($values, __DIR__);
	}
	/**
	 * 写入日志
	 * @param string|array $values
	 * @param string $dir
	 * @return bool|int
	 */
  public function write_log($values, $dir){
		if (is_array($values))
			$values = print_r($values, true);
		// 日志内容
		$content = '[' . date('Y-m-d H:i:s') . ']' . PHP_EOL . $values . PHP_EOL . PHP_EOL;
		try {
			// 文件路径
			$filePath = $dir . '/logs/';
			// 路径不存在则创建
			!is_dir($filePath) && mkdir($filePath, 0755, true);
			// 写入文件
			return file_put_contents($filePath . date('Ymd') . '.log', $content, FILE_APPEND);
		} catch (\Exception $e) {
			return false;
		}
	}

	/**
	 * 写入日志 (使用tp自带驱动记录到runtime目录中)
	 * @param $value
	 * @param string $type
	 * @return bool
	 */
	// function log_write($value, $type = 'yoshop-info'){
	// 	$msg = is_string($value) ? $value : print_r($value, true);
	// 	return Log::write($msg, $type);
	// }


}
